package com.wtf.dsp.admin.util;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.wtf.dsp.admin.constant.TemplateNameRules;
import com.wtf.dsp.admin.core.model.GeneratorContext;
import com.wtf.dsp.admin.core.model.GeneratorInfo;
import com.wtf.dsp.admin.exception.WtfDspException;
import com.wtf.dsp.admin.model.TemplateDefaultDynamicConfig;
import com.wtf.dsp.admin.core.model.table.Column;
import com.wtf.dsp.admin.core.model.table.Table;
import com.wtf.dsp.admin.model.vo.ColumnVO;
import com.wtf.dsp.admin.model.vo.PreviewCodeVO;
import com.wtf.dsp.admin.model.vo.TableVO;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;


import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * description: 代码生成器工具类
 * date: 2022/6/18 10:59
 * @author linhuanyou
 * @email 496558736@qq.com
 * @version 1.0
 */
public class GeneratorUtil {

    public static void generatorTableCode(List<GeneratorInfo> templates, TableVO tableVO, List<ColumnVO> columnVOS, TemplateDefaultDynamicConfig templateDynamicConfigVO, ZipOutputStream zip) {
        GeneratorContext context = generatorTableContext(tableVO,columnVOS,templateDynamicConfigVO);
        //获取模板列表
        for (GeneratorInfo template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template.getGeneratorFileName(), "UTF-8");
            tpl.merge(context.getVelocityContext(), sw);
            try {
                //添加到zip
                GeneratorInfo lastGeneratorInfo = getLastGeneratorInfo(template, context.getTable() == null ? null :context.getTable().getClassName(),templateDynamicConfigVO.getPackageReference(), templateDynamicConfigVO.getModuleName());
                ZipEntry zipEntry = new ZipEntry(lastGeneratorInfo.getGeneratorFilePath());
                zip.putNextEntry(zipEntry);
                IOUtils.write(sw.toString(), zip, "UTF-8");
                IOUtils.closeQuietly(sw);
                zip.closeEntry();
            } catch (IOException e) {
                throw new WtfDspException("渲染模板失败，表名：" + context.getTable().getTableName(), e);
            }
        }
    }

    public static void generatorCommonCode(List<GeneratorInfo> templates, TemplateDefaultDynamicConfig templateDynamicConfigVO, ZipOutputStream zip) {
        GeneratorContext context = generatorCommonContext(templateDynamicConfigVO);
        doGeneratorCode(templates,context,templateDynamicConfigVO,zip);
    }

    private static void doGeneratorCode(List<GeneratorInfo> templates,GeneratorContext context, TemplateDefaultDynamicConfig templateDynamicConfigVO, ZipOutputStream zip){
        //获取模板列表
        for (GeneratorInfo template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template.getGeneratorFileName(), "UTF-8");
            tpl.merge(context.getVelocityContext(), sw);
            try {
                //添加到zip
                GeneratorInfo lastGeneratorInfo = getLastGeneratorInfo(template, context.getTable() == null ? null :context.getTable().getClassName(),templateDynamicConfigVO.getPackageReference(), templateDynamicConfigVO.getModuleName());
                ZipEntry zipEntry = new ZipEntry(lastGeneratorInfo.getGeneratorFilePath());
                zip.putNextEntry(zipEntry);
                IOUtils.write(sw.toString(), zip, "UTF-8");
                IOUtils.closeQuietly(sw);
                zip.closeEntry();
            } catch (IOException e) {
                throw new WtfDspException("渲染模板失败，表名：" + context.getTable().getTableName(), e);
            }
        }
    }

    /**
     * 列名转换成Java属性名
     */
    public static String columnToJava(String columnName) {
        return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
    }

    /**
     * 表名转换成Java类名
     */
    public static String tableToJava(String tableName, String[] tablePrefixArray) {
        if (null != tablePrefixArray && tablePrefixArray.length > 0) {
            for (String tablePrefix : tablePrefixArray) {
                tableName = tableName.replace(tablePrefix, "");
            }
        }
        return columnToJava(tableName);
    }

    /**
     * 获取配置信息
     */
    public static Configuration getConfig() {
        try {
            return new PropertiesConfiguration("generator.properties");
        } catch (ConfigurationException e) {
            throw new WtfDspException("获取配置文件失败，", e);
        }
    }



    /**
     * 获取文件名
     */
    public static GeneratorInfo getLastGeneratorInfo(GeneratorInfo vmTemplate, String className, String packageName, String moduleName) {
        GeneratorInfo lastGeneratorInfo = new GeneratorInfo();
        String generatorFileName = vmTemplate.getGeneratorFileName().endsWith("Application.java") ? moduleName.replaceAll( "\\b\\w", String.valueOf(Character.toUpperCase(moduleName.charAt(0)))) : className;
        generatorFileName = TemplateNameRules.classRules.stream().filter(e->{return vmTemplate.getGeneratorFileName().endsWith(e);}).findFirst().isPresent() ? generatorFileName + vmTemplate.getGeneratorFileName() : vmTemplate.getGeneratorFileName();
        String generatorFilePath = vmTemplate.getGeneratorFilePath().replace("${package}",packageName.replace(".", File.separator)).replace("${module}",moduleName) + generatorFileName;
        lastGeneratorInfo.setGeneratorFileName(generatorFileName);
        lastGeneratorInfo.setGeneratorFilePath(generatorFilePath);
        return lastGeneratorInfo;
    }

    private static String splitInnerName(String name){
        name = name.replaceAll("\\.","_");
        return name;
    }

    public static List<PreviewCodeVO> previewCode(List<GeneratorInfo> templates, TableVO tableVO, List<ColumnVO> columnVOS, TemplateDefaultDynamicConfig templateDynamicConfigVO) {
        List<PreviewCodeVO> dataMap = new ArrayList<>();
        GeneratorContext context = generatorTableContext(tableVO, columnVOS, templateDynamicConfigVO);
        //获取模板列表
        for (GeneratorInfo template : templates) {
            //渲染模板
            PreviewCodeVO previewCodeVO = new PreviewCodeVO();
            GeneratorInfo lastGeneratorInfo = getLastGeneratorInfo(template, context.getTable().getClassName(),templateDynamicConfigVO.getPackageReference(), templateDynamicConfigVO.getModuleName());
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template.getGeneratorFileName(), "UTF-8");
            tpl.merge(context.getVelocityContext(), sw);
            previewCodeVO.setFilePath(lastGeneratorInfo.getGeneratorFilePath().replace(File.separator,"/"));
            previewCodeVO.setCode(sw.toString());
            dataMap.add(previewCodeVO);
        }
        return dataMap;
    }
    private static GeneratorContext generatorTableContext(TableVO tableVO, List<ColumnVO> columnVOS, TemplateDefaultDynamicConfig templateDynamicConfigVO){
        //配置信息
        Configuration config = getConfig();
        boolean hasBigDecimal = false;
        boolean hasList = false;
        //表信息
        Table table = new Table();
        table.setSchemaName(tableVO.getSchemaName());
        table.setTableName(tableVO.getTableName());
        table.setComments(tableVO.getTableComment());
        //表名转换成Java类名
        String className = tableToJava(table.getTableName(), templateDynamicConfigVO.getTablePrefix().split(","));
        table.setClassName(className);
        table.setClassname(StringUtils.uncapitalize(className));

        //列信息
        List<Column> columsList = new ArrayList<>();
        for (ColumnVO columnVO : columnVOS) {
            Column column = new Column();
            column.setColumnName(columnVO.getColumnName());
            column.setDataType(columnVO.getDataType());
            column.setComments(columnVO.getColumnComment());
            column.setExtra(columnVO.getExtra());

            //列名转换成Java属性名
            String attrName = columnToJava(column.getColumnName());
            column.setAttrName(attrName);
            column.setAttrname(StringUtils.uncapitalize(attrName));

            //列的数据类型，转换成Java类型
            String attrType = config.getString(column.getDataType(), columnToJava(column.getDataType()));
            column.setAttrType(attrType);


            if (!hasBigDecimal && "BigDecimal".equals(attrType)) {
                hasBigDecimal = true;
            }
            if (!hasList && "array".equals(column.getExtra())) {
                hasList = true;
            }
            //是否主键
            if ("PRI".equalsIgnoreCase(columnVO.getColumnKey()) && table.getPk() == null) {
                table.setPk(column);
            }

            columsList.add(column);
        }
        table.setColumns(columsList);

        //没主键，则第一个字段为主键
        if (table.getPk() == null) {
            table.setPk(table.getColumns().get(0));
        }

        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("schemaName", table.getSchemaName());
        map.put("tableName", table.getTableName());
        map.put("comments", table.getComments());
        map.put("pk", table.getPk());
        map.put("className", table.getClassName());
        map.put("classname", table.getClassname());
        map.put("pathName", table.getClassname().toLowerCase());
        map.put("columns", table.getColumns());
        map.put("hasBigDecimal", hasBigDecimal);
        map.put("hasList", hasList);
        map.put("package", templateDynamicConfigVO.getPackageReference());
        map.put("moduleName", templateDynamicConfigVO.getModuleName());
        map.put("application", templateDynamicConfigVO.getModuleName().replaceFirst(templateDynamicConfigVO.getModuleName().substring(0,1),templateDynamicConfigVO.getModuleName().substring(0,1).toUpperCase()) + "Application");
        map.put("author", templateDynamicConfigVO.getAuthor());
        map.put("email", templateDynamicConfigVO.getEmail());
        map.put("datetime", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
        VelocityContext context = new VelocityContext(map);
        GeneratorContext generatorContext = new GeneratorContext();
        generatorContext.setVelocityContext(context);
        generatorContext.setTable(table);
        return generatorContext;
    }

    private static GeneratorContext generatorCommonContext(TemplateDefaultDynamicConfig templateDynamicConfigVO){
        //配置信息
        Configuration config = getConfig();
        boolean hasBigDecimal = false;
        boolean hasList = false;
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("hasBigDecimal", hasBigDecimal);
        map.put("hasList", hasList);
        map.put("package", templateDynamicConfigVO.getPackageReference());
        map.put("moduleName", templateDynamicConfigVO.getModuleName());
        map.put("application", templateDynamicConfigVO.getModuleName().replaceFirst(templateDynamicConfigVO.getModuleName().substring(0,1),templateDynamicConfigVO.getModuleName().substring(0,1).toUpperCase()) + "Application");
        map.put("author", templateDynamicConfigVO.getAuthor());
        map.put("email", templateDynamicConfigVO.getEmail());
        map.put("datetime", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
        VelocityContext context = new VelocityContext(map);
        GeneratorContext generatorContext = new GeneratorContext();
        generatorContext.setVelocityContext(context);
        return generatorContext;
    }

    public static void main(String[] args) {
        System.out.println("main" + File.separator + "java" + File.separator + "mapper" + File.separator + "T3" + "Mapper.java");
    }
}
